package com.demo.aop.core;

import lombok.Getter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @description:
 * @author: NOVOTS
 * @date: 2019-04-29 18:12
 */
@Getter
public class ProxyFactory {
    private FyProxy fyProxy;

    /**
     * @redeme:
     * 用来给上层调用
     * 每通过原类和对象，get到一个短裤对象的时候
     * 新建一个FyProxy对象，并将原对象生成的代理对象set近这个fyproxy
     * 达到代理对象和元对象一一对应关系
     * @author  tjh
     * @date 2019/4/29 18:23
     */
    public <T> T getCglibProxy(Class<?>  cls,Object arg){
        fyProxy = new FyProxy();
        Object proxy = cglibProxy(cls,arg);
        fyProxy.setObject(proxy);
        fyProxy.setObject(arg);
        return (T)fyProxy;
    }


    private Object cglibProxy(Class<?> cls, final Object arg) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cls);
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                return doInvoker(arg,method,args);
            }
        });
        return enhancer.create();
    }

    /**
    * @redeme:  获取jdk代理
    * @author  tjh
    * @date 2019/4/29 18:32
    */
    private Object getJdkProxy(Class<?> cls, final Object arg){
        ClassLoader classLoader = cls.getClassLoader();
        Class<?>[] interfaces = cls.getInterfaces();
        InvocationHandler invocationHandler = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return doInvoker(arg,method,args);
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }

    /**
    * @redeme:  代理对象执行方法时内部的东西
    * @author  tjh
    * @date 2019/4/29 18:33
    */
    private Object doInvoker(Object arg,Method method,Object... args) {
        Object result = null;
        fyProxy.doAfter(method,args);
        try {
            result = method.invoke(arg,args);
            fyProxy.doAfter(method,result);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }
}
